闲话 22.11.22

闲话

这个

?突然没什么好说的了
今天模拟赛让我体验了别人 csp 的四分之三
别人:看T2。哦,会了。看T1。哦,会了。看T3。哦,会了。看T4。哦,会了。好像 AK 了,非常感动。
我今天:看T2。哦,会了。看T4。哦,会了。看T3。……哦,会了。看T1。……好像 AK ,不是很感动。
于是是四分之三(

今天 221122 ,是回文!

杂题

ARC146C

请输出满足下述条件的集合 S{0,1,2,,2n1} 的个数对 998244353 取模后的结果。

  • 对于所有 S 的非空子集 T,均满足下列条件之一:
    • |T| 为奇数;
    • T中所有元素的异或和不为 0

1n2×105

考虑向已经满足条件的集合中加入元素得到新的集合。设 fi 为大小为 i 的满足条件的集合。根据定义有 f0=1, f1=2n

设一个满足条件的集合为 SS 的一个大小为奇数的子集为 TT 内元素的异或和为 x。如果我们将 x 加入了集合 S 得到 S,则 T{x}S,而 2|T{x}|,因此 S 不满足条件。
由此可以看到,对于一个满足条件的集合 S,向其中加入任意一个奇大小子集的异或和会使得其不再满足条件。同时,由于 S 是满足条件的集合,任意两个奇大小子集的异或和都不同,因为反之可以取这两个子集中只出现过一次的元素作为一个偶大小子集,而这个子集的异或和为 0

因此我们可以发现,大小为 i 的集合可以加入 [][ i ]=2n2i1 种互不相同的元素得到大小为 i+1 的集合。而每个 i+1 大小集合通过此方法都被计数了 i+1 次,因此有转移

fi+1=1i+1(fi×(2n2i1))

预处理 2 的幂次与逆元后复杂度为 O(n)

推一下 APJifengc 的线代版题解
\疾风c/\疾风c/\疾风c/\疾风c/

code
#include <bits/stdc++.h>
using namespace std; 
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
const int N = 2e5 + 10, mod = 998244353;
int n, f[N], inv[N], pw[N], ans;
signed main() {
    cin >> n; 
    pw[0] = 1; rep(i,1,n + 1) { pw[i] = (pw[i - 1] << 1); if (pw[i] >= mod) pw[i] -= mod; }
    f[0] = 1; f[1] = pw[n];
    inv[0] = inv[1] = 1; rep(i,2,n+1) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
    rep(i,2,n + 1) f[i] = 1ll * f[i - 1] * (pw[n] - pw[i - 2] + mod) % mod * inv[i] % mod;
    rep(i,0,n + 1) { ans += f[i]; if (ans >= mod) ans -= mod; };
    cout << ans << '\n';
}



ARC087E

对于两个字符串 s,t , 如果 s 不是 t 的前缀且 t 不是 s 的前缀,则称他们前缀互不包含。

给定一个正整数 L,如果一个字符串集合 S 符合下列条件,则我们称他为好的集合:

  • S 中的每个字符串的长度都在 1L 之间(包括),并且只包含字符 01
  • S 中的每两个的字符串都前缀互不包含

我们有一个好的集合 S=s1,s2...,sn,Alice 和 Bob 在玩一个游戏,他们轮流做下列操作:

  • S 中添加一个新字符串,并使 S 仍是好的集合

无法进行这个操作的人输掉游戏。假设二人都按最优策略进行游戏,求谁会赢。

1N105, 1L1018, |si|105

首先建出一棵深度为 L 的 Trie,其是一棵满二叉树。(不用真建)
然后我们能发现,假如我们选了这上面的一条链,那链尾的子树上节点和链上节点都是不能选的。容易发现这样的一条链把原树划分成了更多更小的满二叉树。这就是 ICG 图上由大到小的一系列边。
观察这些二叉树。假设我们选了根节点,则无法再选择,该局面必败。假设我们选了深度为 i 的节点,那么会剩余 i 棵深度为 xj s.t. 1ji 的满二叉树。

则有

SG(x)=mexi=1x(j=1iSG(xj))

我们断言,SG(x)=lowbit x。证明考虑数学归纳法(
于是可以直接把 S 建成 Trie ,然后在 Trie 上 dp。
总时间复杂度 O(|si|)

code
#include <bits/stdc++.h>
using namespace std; 
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
const int N = 1e5 + 100;
int n, trie[N][2], ed[N], mlc = 1;
long long l, ans;
char ch[N];
#define lowbit(x) ((x) & -(x))
queue<pair<int,int> > que;
signed main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); 
    cin >> n >> l; 
    rep(i,1,n) {
        cin >> ch + 1;
        int len = strlen(ch + 1), ptr = 1;
        rep(j,1,len) {
            if (!trie[ptr][ch[j] - '0']) trie[ptr][ch[j] - '0'] = ++ mlc;
            ptr = trie[ptr][ch[j] - '0'];
        } ed[ptr] = 1;
    }
    que.emplace(1, 0);
    while (que.size()) {
        auto [u, dep] = que.front(); que.pop();
        if (ed[u]) continue ;
        if (trie[u][0]) que.emplace(trie[u][0], dep + 1);
        else ans ^= lowbit(l - dep);
        if (trie[u][1]) que.emplace(trie[u][1], dep + 1);
        else ans ^= lowbit(l - dep);
    }
    puts(ans ? "Alice" : "Bob");
}



CF1000F

给定一个长度为 n 的序列 a。有 m 个询问,每次询问给定一个区间 [l,r],如果这个区间里存在只出现一次的数,输出这个数(有多个输出任意一个即可),没有就输出0。

n,m5×105

i 左侧第一个与 ai 相同的位置为 li,右侧第一个位置为 ri
容易发现一次询问 (l,r) 如果满足 li<lir<ri 则输出 i 即可。

询问离线。首先在全局维护一个 bool 数组 bbi 表示 i 是否仍然可以作为答案。
一次询问 (l,r)r 位置的询问桶里插入 l。一次修改在 i 位置的修改桶里插入 [li+1,i] 的加入 i,在 ri 位置的修改桶里插入 [li+1,i] 的删除 i

在线段树的每个节点维护一个链表,标记永久化。区间加入 i 时正常加入 O(logn) 个节点,并将 bi 置为 true。区间删除时懒惰删除,将 bi 标记为 false 即可。
查询时顺着从根查到叶子,过程中顺序扫描路径上每个链表,并将不合法节点删除。查到后即可直接返回。

根据均摊,总时间复杂度 O(nlogn)

没写代码。
upd :
写了。
码量很小,不到 2k。本来想练码力写的没想到十五分钟写完了
但是跑得很慢
比 nmd 莫队归并排序树都慢
我不是很理解 是不是我的复杂度有问题?

这里也放个码
#include <bits/stdc++.h>
#define rep(i,s,t) for (int i = (s), i##END = (t) + 1; i < i##END; ++ i)
#define pre(i,s,t) for (int i = (s), i##END = (t) - 1; i > i##END; -- i)
using namespace std;
const int N = 5e5 + 10;
int n, m, a[N], t1, t2, stk[N], top, l[N], r[N], vis[N], ans[N]; 
struct query { int pos, id; }; vector<query> qy[N];
struct update { int l, r, v, cont; }; vector<update> ud[N];

bool inuse[N];
struct SegmentBeats {
    #define ls (p << 1)
    #define rs (p << 1 | 1)
    list<pair<int,int> > seg[N << 2];
    void upd(int L, int R, int val, int p = 1, int l = 1, int r = n) {
        if (L <= l and r <= R) return seg[p].emplace_back(R, val), void();
        int mid = l + r >> 1;
        if (L <= mid) upd(L, R, val, ls, l, mid);
        if (mid < R) upd(L, R, val, rs, mid+1, r);
    }
    int query(int pos, int p = 1, int l = 1, int r = n) {
        for (auto x = seg[p].begin(); x != seg[p].end(); x = seg[p].erase(x)) if (inuse[x->first]) return x->second;
        if (l == r) return 0; 
        int mid = l + r >> 1;
        if (pos <= mid) return query(pos, ls, l, mid);
        else return query(pos, rs, mid+1, r);
    }
} Tr;

signed main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n; rep(i,1,n) cin >> a[i];
    cin >> m; rep(i,1,m) cin >> t1 >> t2, qy[t2].push_back( {t1, i} );
    rep(i,1,n) l[i] = vis[a[i]], vis[a[i]] = i;
    rep(i,1,n) vis[i] = n + 1;
    pre(i,n,1) r[i] = vis[a[i]], vis[a[i]] = i;
    rep(i,1,n) ud[i].push_back( {l[i] + 1, i, a[i], 1} ), ud[r[i]].push_back( {0, i, a[i], -1} );
    rep(i,1,n) {
        for (auto x : ud[i]) 
            if (x.cont == 1) inuse[x.r] = 1, Tr.upd(x.l, x.r, x.v);
            else inuse[x.r] = 0;
        for (auto x : qy[i]) ans[x.id] = Tr.query(x.pos);
    }
    rep(i,1,m) cout << ans[i] << '\n';
}
posted @   joke3579  阅读(78)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示